<template>
    <el-form ref="formRef" :model="model" :inline="formData?.inline ?? false"
        :hide-required-asterisk="formData?.hideRequiredAsterisk ?? false"
        :require-asterisk-position="formData?.requireAsteriskPosition ?? 'left'"
        :label-posiiton="formData?.labelPosition ?? 'left'" :label-width="formData?.labelWidth || 'auto'">
        <el-row :gutter="14">
            <template v-for="(item, index) in formData.list" :key="index">
                <el-col v-if="!item.hide" :span="item.span || formData.span || 12">
                    <el-form-item v-if="!item.hide" :prop="item.prop" :label="item.label" :rules="itemRules(item)">
                        <template v-if="item.type === 'inputGroup'">
                            <CuInput v-model:value="model[item.prop]" :size="formData.size || 'default'" :item="item">
                                <template v-if="item?.extra?.prepend" #prepend>
                                    <el-form-item :prop="item.extra.prepend.prop"
                                        :rules="itemRules(item?.extra?.prepend)">
                                        <template v-if="item?.extra?.prepend.type === 'select'">
                                            <CuSelect v-model:value="model[item.extra.prepend.prop]" class="!m-0"
                                                :size="formData.size || 'default'" :item="item.extra.prepend" />
                                        </template>
                                    </el-form-item>
                                </template>
                                <template v-if="item?.extra?.append" #append>
                                    <el-form-item :prop="item.extra.append.prop" :rules="itemRules(item)">
                                        <template v-if="item?.extra?.append.type === 'select'">
                                            <CuSelect v-model:value="model[item.extra.append.prop]"
                                                :size="formData.size || 'default'" :item="item.extra.append"
                                                class="!m-0 !w-80px" />
                                        </template>
                                    </el-form-item>
                                </template>
                            </CuInput>
                        </template>
                        <template v-else>
                            <component class="w-full" :class="item?.extra?.class" v-model:value="model[item.prop]"
                                :is="componentMap[item.type as keyof typeof componentMap]"
                                :size="formData.size || 'default'" :item="item" />
                        </template>
                    </el-form-item>
                </el-col>
            </template>
        </el-row>
    </el-form>
</template>

<script lang="ts" setup>
import { ref, watch, computed } from 'vue'
import { debounce } from 'lodash'
import type { FormInstance } from 'element-plus'
import type { AnyObject } from '@/api/type'
import type { FormDataDto, FormItemDto } from './type'
import CuSelect from '../base-component/cu-select.vue'
import CuInput from '../base-component/cu-input.vue'
import CuTextarea from '../base-component/cu-textarea.vue'
import CuDate from '../base-component/cu-date.vue'
import CuDaterange from '../base-component/cu-daterange.vue'
import CuRadioGroup from '../base-component/cu-radio-group.vue'
import CuCheckboxGroup from '../base-component/cu-checkbox-group.vue'
import CuUploadImg from '../base-component/cu-upload-img.vue'
import CuSwitch from '../base-component/cu-switch.vue'
import CuInputNumber from '../base-component/cu-input-number.vue'
import { wait } from '@/utils/utils'

const props = defineProps<{
    value: AnyObject
    formData: FormDataDto
}>()
const componentMap = {
    'select': CuSelect,
    'input': CuInput,
    'textarea': CuTextarea,
    'date': CuDate,
    'daterange': CuDaterange,
    'radioGroup': CuRadioGroup,
    'checkboxGroup': CuCheckboxGroup,
    'uploadImage': CuUploadImg,
    'switch': CuSwitch,
    'inputNumber': CuInputNumber,
}

const model = ref<AnyObject>({} as AnyObject)

const formRef = ref<FormInstance>()

const itemRules = computed(() => {
    return (item: FormItemDto) => {
        const requredRules = item.required ? [{ required: true, message: `${item.label}不能为空`, trigger: 'change' }] : []
        return [...requredRules, ...(item.rules || [])]
    }
})

const emits = defineEmits(['valueChanged', 'update:formData', 'update:value'])
/**
 * 验证表单
 */
const handleValidate = async () => {
    if (!formRef.value) return
    const valid = await formRef.value.validate()
    return valid
}
/**
 * 重置表单
 */
const resetFields = () => {
    if (!formRef.value) return
    formRef.value.resetFields()
}

/**
 * 验证表单字段
 */
const validateField = (prop: string) => {
    if (!formRef.value) return
    formRef.value.validateField(prop)
}

/**
 * 清除表单字段
 */
const clearFields = (prop?: string) => {
    if (!formRef.value) return
    formRef.value.clearValidate(prop)
}

/**
 * 获取表单值
 */
const getFormValue = () => {
    return model.value
}

/**
 * 设置表单值
 */
const setFormValue = async (defaultValue?: AnyObject) => {
    if (defaultValue) {
        for (const key in defaultValue) {
            model.value[key] = defaultValue[key]
        }
    } else {
        Object.values(props.formData.list).forEach(i => {
            model.value[i.prop] = i.defaultValue ?? ''
            if (i.type === 'inputGroup') {
                if (i.extra?.prepend) {
                    model.value[i.extra.prepend.prop] = i.extra.prepend.defaultValue ?? ''
                }
                if (i.extra?.append) {
                    model.value[i.extra.append.prop] = i.extra.append.defaultValue ?? ''
                }
            }
        })
    }
    await wait(0)
    clearFields()
}

defineExpose({
    handleValidate,
    resetFields,
    clearFields,
    validateField,
    getFormValue,
    setFormValue
})

watch(() => props.value, (newval) => {
    model.value = newval
}, {
    immediate: true
})

watch(model, debounce((newval) => {
    emits('update:value', newval)
}, 300), {
    deep: true
})

</script>
<style lang="scss" scoped>
:deep(.width-full .el-input__wrapper) {
    width: calc(100% - 22px);
}
</style>
